//////////////////////////////////////////////////////////////////////////
// PeekPocket - the hassle-free WiFi scanner for Windows Mobile
// coded by dzolee
// http://dzolee.blogspot.com
//
// WifiPeek: provides access to WiFi information using NDISUIO
// (some code from Daniel Strigl and Pier Paolo Peri)
//////////////////////////////////////////////////////////////////////////

#include "WifiPeek.h"

#define LOCK EnterCriticalSection(&m_Lock);
#define UNLOCK LeaveCriticalSection(&m_Lock);

//my simple logging routines
#include "log.h"

//IP helper API
#include <IPHlpApi.h>

//////////////////////////////////////////////////////////////////////////
CWifiPeek::CWifiPeek()
{
	m_hNDUIO=NULL;
	InitializeCriticalSection(&m_Lock);
	OpenDriver();

	//by xlos
	HRESULT hr = E_FAIL;
	hr = m_GPSController.InitDevice(&m_GPSSink);
	if (FAILED(hr))
	{
		//for debugging
		int i = 0;
	}
	

}

//////////////////////////////////////////////////////////////////////////
CWifiPeek::~CWifiPeek()
{
	if(m_hNDUIO != NULL)
	{
		CloseDriver();
	}
	DeleteCriticalSection(&m_Lock);
}

//////////////////////////////////////////////////////////////////////////
//get list of usable adapters
bool CWifiPeek::GetAdapters(LPWSTR pDest, DWORD &dwBufSizeBytes)
{
HANDLE hFile;
BYTE Buffer[2048];
void *pvBuf;
WCHAR TmpBuf[1024];
WCHAR *pszOut;
DWORD dwRet;
bool retval;

	if(pDest == NULL || dwBufSizeBytes < sizeof(WCHAR))
	{
		dwBufSizeBytes=0;
		return false;
	}

	logmsg("%s starting...", __FUNCTION__);

	LOCK;
	retval=false;
	//open NDIS driver
	hFile=CreateFile(L"NDS0:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
	if(hFile != INVALID_HANDLE_VALUE)
	{
		pvBuf=(void *)(&Buffer[0]);
		dwRet=sizeof(Buffer);
		if(DeviceIoControl(hFile, IOCTL_NDIS_GET_ADAPTER_NAMES, NULL, 0, pvBuf, sizeof(Buffer), &dwRet, NULL))
		{
			//adapter list ok.
			LPWSTR pszStr;
			dwRet=0;
			pszOut=TmpBuf;

			//no string classes used, so no MFC or ATL dependency.
			for(pszStr=(LPWSTR)pvBuf; *pszStr; pszStr+=wcslen(pszStr)+1)
			{
				logmsg("%s: found adapter %S...", __FUNCTION__, pszStr);
				//check if adapter name is ok, skip infrared, gprs, ActiveSync etc.
				if(wcsicmp(pszStr, L"ASYNCMAC1") && \
					wcsicmp(pszStr, L"IRSIR1") && \
					wcsicmp(pszStr, L"L2TP1") && \
					wcsicmp(pszStr, L"PPTP1") && \
					wcsicmp(pszStr, L"RNDISFN1") && \
					wcsicmp(pszStr, L"WWAN1") && \
					wcsicmp(pszStr, L"XSC1_IRDA1") && IsWireless(pszStr))
				{						
					//not the first adapter?
					if(pszOut != TmpBuf)
					{
						//append separator
						wcscat(pszOut, L",");
						pszOut++;
						dwRet+=sizeof(WCHAR);
					}
					wcscpy(pszOut, pszStr);
					pszOut+=wcslen(pszStr);
					dwRet+=sizeof(WCHAR) * wcslen(pszStr);
					logmsg("%s: adapter ok: %S...", __FUNCTION__, pszStr);
				}
			}
			//return required buffer size anyway
			dwBufSizeBytes=dwRet;

			//if buffer large enough, copy adapter names
			if(dwBufSizeBytes >= dwRet)
			{
				wcsncpy(pDest, TmpBuf, dwRet);
				retval=true;
			}
			//otherwise will return false
			//..
		}
		CloseHandle(hFile);
	}
	UNLOCK;
	logmsg("%s finished.", __FUNCTION__);
	return retval;
}

//////////////////////////////////////////////////////////////////////////
//see if an adapter is wireless - courtesy Daniel Strigl
bool CWifiPeek::IsWireless(LPWSTR pAdapter)
{
DWORD dwBytesReturned = 0;  
NDISUIO_QUERY_OID NDISUIOQueryOid = {0};  

	logmsg("%s starting...", __FUNCTION__);

	//hardwired check - to avoid lockup.
	//on a FS 720 with WM2003, PeekPocket froze in this function, probably DeviceIoControl
	if(wcsicmp(pAdapter, L"TIACXWLN1") == 0)
	{
		logmsg("adapter %S is hardcoded to be wireless", pAdapter);
		return true;
	}

	//another hardcoded adapter - used in FS Loox and HTCs too
	//on HTC there was a problem getting the phys medium
	if(wcsicmp(pAdapter, L"TNETWLN1") == 0)
	{
		logmsg("adapter %S is hardcoded to be wireless", pAdapter);
		return true;
	}


	NDISUIOQueryOid.ptcDeviceName = (PTCHAR) pAdapter;  
	NDISUIOQueryOid.Oid = OID_GEN_PHYSICAL_MEDIUM;  

	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_QUERY_OID_VALUE,  
		&NDISUIOQueryOid, sizeof(NDISUIOQueryOid),  
		&NDISUIOQueryOid, sizeof(NDISUIOQueryOid),  
		&dwBytesReturned, NULL))  
	{  
		//printf("Function \"DeviceIoControl\" (OID_GEN_PHYSICAL_MEDIUM) failed (0x%08x).\n",   
		logmsg("%s: cannot query adapter %S phys medium. Err: %d", __FUNCTION__, pAdapter, GetLastError());
		//this requires further testing, especially with older devices.
		return false;
	}

	if (*((PNDIS_PHYSICAL_MEDIUM) NDISUIOQueryOid.Data) != NdisPhysicalMediumWirelessLan)  
	{  
		//printf("Device \"%s\" is no wireless adapter.\n", CTtoA(pszAdapter));  
		logmsg("%s: adapter %S is not wireless.", __FUNCTION__, pAdapter);
		return false;
	}

	//yupps it is wireless!
	logmsg("%s: adapter %S is wireless.", __FUNCTION__, pAdapter);
	return true;
}

//////////////////////////////////////////////////////////////////////////
//open the NDISUIO driver
bool CWifiPeek::OpenDriver()
{
HANDLE hDev;

	//already opened?
	if(m_hNDUIO != NULL)
	{
		logmsg("%s: driver already opened!", __FUNCTION__);
		return true;
	}

	hDev=CreateFile(NDISUIO_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, INVALID_HANDLE_VALUE);
	if(hDev == INVALID_HANDLE_VALUE)
	{
		logmsg("%s: failed to open NDISUIO driver. Err: %d", __FUNCTION__, GetLastError());
		return false;
	}
	else
	{
		m_hNDUIO=hDev;
		logmsg("%s: opened NDISUIO driver ok.", __FUNCTION__);
		return true;
	}
}

//////////////////////////////////////////////////////////////////////////
//at the end, close NDISUIO handle
void CWifiPeek::CloseDriver()
{
	CloseHandle(m_hNDUIO);
	m_hNDUIO=NULL;
	logmsg("%s: closing driver.", __FUNCTION__);
}

//////////////////////////////////////////////////////////////////////////
//initiate station scanning
bool CWifiPeek::RefreshBSSIDs(LPWSTR pAdapter)
{
NDISUIO_SET_OID nso;
DWORD dwBytesRet;
bool retval;

	LOCK;
	nso.ptcDeviceName = pAdapter;
	nso.Oid = OID_802_11_BSSID_LIST_SCAN;

	dwBytesRet=0;
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_SET_OID_VALUE, (void *)&nso, sizeof(NDISUIO_SET_OID), NULL, 0, &dwBytesRet, NULL))
	{
		logmsg("%s: failed. Err: %d", __FUNCTION__, GetLastError());
		retval=false;
	}
	else
	{
		logmsg("%s: succeeded.", __FUNCTION__);
		retval=true;
	}
	UNLOCK;
	return retval;
}

//////////////////////////////////////////////////////////////////////////
//get a list of currently visible stations
bool CWifiPeek::GetBSSIDs(LPWSTR pAdapter, struct BSSIDInfo *pDest, DWORD &dwBufSizeBytes, DWORD &dwReturnedItems)
{
PNDISUIO_QUERY_OID pNQO;
DWORD dwBytesRet;
BYTE Buffer[8192], *pByte;
PNDIS_802_11_BSSID_LIST_EX pList;
int i;

	if(pDest == NULL)
	{
		dwReturnedItems=0;
		logmsg("%s: null pointer.", __FUNCTION__);
		return false;
	}

	LOCK;	
	pNQO=(PNDISUIO_QUERY_OID)Buffer;

	pNQO->ptcDeviceName = pAdapter;
	pNQO->Oid=OID_802_11_BSSID_LIST;

	// Run query
	dwBytesRet = 0;
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_QUERY_OID_VALUE, (void *)pNQO, 8192, (void *)pNQO, 8192, &dwBytesRet, NULL))
	{
		logmsg("%s: failed to get list. Err: %d", __FUNCTION__, GetLastError());
		UNLOCK;
		return false;
	}

	pList=(PNDIS_802_11_BSSID_LIST_EX)&pNQO->Data;
	dwReturnedItems=pList->NumberOfItems;

	logmsg("%s: received %d entries.", __FUNCTION__, dwReturnedItems);

	//first item in array
	PNDIS_WLAN_BSSID_EX pItem=pList->Bssid;

	for(i=0; i<dwReturnedItems; i++)
	{
		logmsg("%s: processing entry: %d of %d", __FUNCTION__, i, dwReturnedItems);

		//get MAC add
		memcpy(pDest[i].BSSID, pItem->MacAddress, sizeof(pItem->MacAddress));

		//zero name		
		memset(pDest[i].SSID, 0, sizeof(pDest[i].SSID));

		//if returned string size looks ok, use that value
		if(pItem->Ssid.SsidLength != 0 && pItem->Ssid.SsidLength < sizeof(pItem->Ssid.Ssid))
		{
			mbstowcs(pDest[i].SSID, (char *)pItem->Ssid.Ssid, pItem->Ssid.SsidLength);
		}
		else
		{
			//otherwise use string length
			mbstowcs(pDest[i].SSID, (char *)pItem->Ssid.Ssid, sizeof(pItem->Ssid.Ssid));
		}

		//if name is empty, then construct one derived from MAC add
		if(wcslen(pDest[i].SSID) == 0)
		{
			wsprintf(pDest[i].SSID, _T("NoName-%02x%02x%02x%02x%02x%02x"), pDest[i].BSSID[0], pDest[i].BSSID[1], pDest[i].BSSID[2], pDest[i].BSSID[3], pDest[i].BSSID[4], pDest[i].BSSID[5]);
		}

		logmsg("%s: Current MAC is %02x%02x%02x%02x%02x%02x", __FUNCTION__, pDest[i].BSSID[0], pDest[i].BSSID[1], pDest[i].BSSID[2], pDest[i].BSSID[3], pDest[i].BSSID[4], pDest[i].BSSID[5]);

		//RSSI takes 4 bytes but may be a 16 or 32 bit value.
		if(sizeof(NDIS_802_11_RSSI) == 4)
		{
			BYTE *p;

			p=(BYTE *)&pItem->Rssi;
			//if it is a 16 bit value, the first 2 bytes are zeroes and the last one is a 0xff,
			//since the signal strength is a negative value
			if(p[0] == 0 && p[1] == 0 && p[3] == 0xff)			
			{
				//a short taken from memory and cast to int
				pDest[i].RSSI=(int) (*((short *) (&p[2])));
			}
			else
			{
				//no hassle, it is a 32-bit value			
				pDest[i].RSSI=pItem->Rssi;
			}
		}
		else
		{
			//something's wrong
			pDest[i].RSSI=0;
		}

		//decode channel number
		if(pItem->Configuration.DSConfig > 14)
		{
			pDest[i].Channel=(pItem->Configuration.DSConfig - 2407000) / 5000;
		}
		else
		{
			pDest[i].Channel=pItem->Configuration.DSConfig;
		}
		pDest[i].Auth=pItem->Privacy;
		pDest[i].Infastructure=pItem->InfrastructureMode;

		//If WPA or WPA2 are enabled, there must be a corresponding IE, so we change Auth appropriately
		if(pItem->IELength > 0)
		{
			int proto = 0;

			logmsg("%s: GetAuthMode starting: ie_len: %d", __FUNCTION__, pItem->IELength);

			proto = GetAuthModeFromIEs(pItem->IEs, pItem->IELength);
			if(proto > 0)
			{
				pDest[i].Auth=proto;
			}

			logmsg("%s: GetAuthMode result: ", __FUNCTION__, proto);
		}

		//some pointer magic...actually pItem->Length was not sizeof(NDIS_WLAN_BSSID)
		//so use returned length
		pByte=(BYTE *)pItem;
		pByte+=pItem->Length;
		pItem=(PNDIS_WLAN_BSSID_EX)pByte;
		logmsg("%s: processed one entry.", __FUNCTION__);
	}//for

	UNLOCK;
	logmsg("%s: returning.", __FUNCTION__);
	return true;
}

//////////////////////////////////////////////////////////////////////////
//Get the MAC address of a connected AP. Idea from Daniel Strigl.
bool CWifiPeek::GetPreferredMACAddress(LPWSTR pAdapter, BYTE *pCurrentMac)
{
BYTE pBuffer[sizeof(NDISUIO_QUERY_OID) + sizeof(NDIS_802_11_MAC_ADDRESS)];
PNDISUIO_QUERY_OID pNDISUIOQueryOid;
DWORD dwBytesReturned;

	pNDISUIOQueryOid=(PNDISUIO_QUERY_OID) pBuffer;

	pNDISUIOQueryOid->ptcDeviceName = (PTCHAR) pAdapter;
	pNDISUIOQueryOid->Oid = OID_802_11_BSSID;

	dwBytesReturned=0;
	logmsg("%s starting...", __FUNCTION__);

	LOCK;	
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_QUERY_OID_VALUE, 
		pBuffer, sizeof(pBuffer),
		pBuffer, sizeof(pBuffer),
		&dwBytesReturned, NULL))
	{
		UNLOCK;	
		logmsg("%s finished: DeviceIoControl returned zero value. Err: %d", __FUNCTION__, GetLastError());
		return false;
	}
	UNLOCK;	

	if(dwBytesReturned > 0)
	{
		memcpy(pCurrentMac, pNDISUIOQueryOid->Data, sizeof(NDIS_802_11_MAC_ADDRESS));
	}
	else
	{
		logmsg("DeviceIoControl returned zero bytes of data in %s", __FUNCTION__);
	}

	logmsg("%s succeeded.", __FUNCTION__);
	return true;
}

//////////////////////////////////////////////////////////////////////////
bool CWifiPeek::Disconnect(LPWSTR pAdapter)
{
DWORD dwBytesReturned;

	logmsg("%s starting..", __FUNCTION__);

	NDISUIO_SET_OID NDISUIOSetOid = {0};
	NDISUIOSetOid.ptcDeviceName = (PTCHAR) pAdapter;
	NDISUIOSetOid.Oid = OID_802_11_DISASSOCIATE;

	dwBytesReturned=0;

	LOCK;
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_SET_OID_VALUE, 
		&NDISUIOSetOid, sizeof(NDISUIOSetOid), 
		NULL, 0, 
		&dwBytesReturned, NULL))
	{
		UNLOCK;
		logmsg("%s failed with error code %d", __FUNCTION__, GetLastError());
		return false;
	}

	ReleaseIpAddress(pAdapter);
	UNLOCK;

	logmsg("%s succeeded.", __FUNCTION__);
	return true;
}

//////////////////////////////////////////////////////////////////////////
bool CWifiPeek::PrepareToConnect(LPWSTR pAdapter, int iInfrastructureType)
{
	logmsg("%s starting..", __FUNCTION__);
	if(false == SetInfrastructureMode(pAdapter, iInfrastructureType))
	{
		return false;
	}
	if(false == SetPrivacyFilter(pAdapter))
	{
		return false;
	}
	if(false == SetAuthenticationMode(pAdapter))
	{
		return false;
	}
	if(false == SetEncryptionStatus(pAdapter))
	{
		return false;
	}

	logmsg("%s succeeded.", __FUNCTION__);
	return true;
}

//////////////////////////////////////////////////////////////////////////
//PrepareToConnect helpers: SetXXXXX
bool CWifiPeek::SetInfrastructureMode(LPWSTR pAdapter, int iInfrastructureType)
{
DWORD dwBytesReturned;

	logmsg("%s started...", __FUNCTION__);

	BYTE pBuffer[sizeof(NDISUIO_SET_OID) + sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)];
	PNDISUIO_SET_OID pNDISUIOSetOid = (PNDISUIO_SET_OID) pBuffer;
	PNDIS_802_11_NETWORK_INFRASTRUCTURE pInfrastructureMode = (PNDIS_802_11_NETWORK_INFRASTRUCTURE) pNDISUIOSetOid->Data;

	pNDISUIOSetOid->ptcDeviceName = (PTCHAR) pAdapter;
	pNDISUIOSetOid->Oid = OID_802_11_INFRASTRUCTURE_MODE;
	*pInfrastructureMode = (_NDIS_802_11_NETWORK_INFRASTRUCTURE)iInfrastructureType;

	dwBytesReturned=0;

	LOCK;
	if (!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_SET_OID_VALUE, 
		pBuffer, sizeof(pBuffer), 
		NULL, 0, 
		&dwBytesReturned, NULL))
	{
		UNLOCK;
		logmsg("%s failed with error code %d", __FUNCTION__, GetLastError());
		return false;
	}
	UNLOCK;

	logmsg("%s succeeded.", __FUNCTION__);
	return true;	
}

//////////////////////////////////////////////////////////////////////////
bool CWifiPeek::SetPrivacyFilter(LPWSTR pAdapter)
{
DWORD dwBytesReturned;

	logmsg("%s started...", __FUNCTION__);

	BYTE pBuffer[sizeof(NDISUIO_SET_OID) + sizeof(NDIS_802_11_PRIVACY_FILTER)];
	PNDISUIO_SET_OID pNDISUIOSetOid = (PNDISUIO_SET_OID) pBuffer;
	PNDIS_802_11_PRIVACY_FILTER pPrivacyFilter = (PNDIS_802_11_PRIVACY_FILTER) pNDISUIOSetOid->Data;

	pNDISUIOSetOid->ptcDeviceName = (PTCHAR) pAdapter;
	pNDISUIOSetOid->Oid = OID_802_11_PRIVACY_FILTER;
	*pPrivacyFilter = Ndis802_11PrivFilterAcceptAll;

	dwBytesReturned=0;

	LOCK;
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_SET_OID_VALUE, 
		pBuffer, sizeof(pBuffer), NULL, 0, &dwBytesReturned, NULL))
	{
		UNLOCK;
		logmsg("%s failed with error code %d", __FUNCTION__, GetLastError());
		return false;
	}
	UNLOCK;

	logmsg("%s succeeded.", __FUNCTION__);
	return true;	
}

//////////////////////////////////////////////////////////////////////////
bool CWifiPeek::SetAuthenticationMode(LPWSTR pAdapter)
{
DWORD dwBytesReturned;

	logmsg("%s started...", __FUNCTION__);
	
	BYTE pBuffer[sizeof(NDISUIO_SET_OID) + sizeof(NDIS_802_11_AUTHENTICATION_MODE)];
	PNDISUIO_SET_OID pNDISUIOSetOid = (PNDISUIO_SET_OID) pBuffer;
	PNDIS_802_11_AUTHENTICATION_MODE pAuthenticationMode =
		(PNDIS_802_11_AUTHENTICATION_MODE) pNDISUIOSetOid->Data;

	pNDISUIOSetOid->ptcDeviceName = (PTCHAR) pAdapter;
	pNDISUIOSetOid->Oid = OID_802_11_AUTHENTICATION_MODE;
	*pAuthenticationMode = Ndis802_11AuthModeOpen;

	dwBytesReturned=0;

	LOCK;	
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_SET_OID_VALUE, 
		pBuffer, sizeof(pBuffer), 
		NULL, 0, &dwBytesReturned, NULL))
	{
		UNLOCK;
		logmsg("%s failed with error code %d", __FUNCTION__, GetLastError());
		return false;
	}
	UNLOCK;

	logmsg("%s succeeded.", __FUNCTION__);
	return true;	
}

//////////////////////////////////////////////////////////////////////////
bool CWifiPeek::SetEncryptionStatus(LPWSTR pAdapter)
{
DWORD dwBytesReturned;

	logmsg("%s started...", __FUNCTION__);

	BYTE pBuffer[sizeof(NDISUIO_SET_OID) + sizeof(NDIS_802_11_ENCRYPTION_STATUS)];
	PNDISUIO_SET_OID pNDISUIOSetOid = (PNDISUIO_SET_OID) pBuffer;
	PNDIS_802_11_ENCRYPTION_STATUS pEncryptionStatus =
		(PNDIS_802_11_ENCRYPTION_STATUS) pNDISUIOSetOid->Data;

	pNDISUIOSetOid->ptcDeviceName = (PTCHAR) pAdapter;
	pNDISUIOSetOid->Oid = OID_802_11_ENCRYPTION_STATUS;
	*pEncryptionStatus = Ndis802_11EncryptionDisabled;

	dwBytesReturned=0;

	LOCK;
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_SET_OID_VALUE, 
		pBuffer, sizeof(pBuffer), NULL, 0, &dwBytesReturned, NULL))
	{
		UNLOCK;
		logmsg("%s failed with error code %d", __FUNCTION__, GetLastError());
		return false;
	}
	UNLOCK;

	logmsg("%s succeeded.", __FUNCTION__);
	return true;	
}

//////////////////////////////////////////////////////////////////////////
bool CWifiPeek::ConnectToAPName(LPWSTR pAdapter, LPWSTR pAPName)
{
DWORD dwBytesReturned;
char sAPName[256];

	logmsg("%s started...", __FUNCTION__);

	//zero string
	memset((void *)sAPName, 0, sizeof(sAPName));

	//convert unicode AP name to ansi
	if(WideCharToMultiByte(CP_ACP, 0, pAPName, -1, &sAPName[0], 255, NULL, NULL) > 0)
	{
		//ok, ansi string created!
	}
	else
	{
		logmsg("%s: WideCharToMultiByte failed.", __FUNCTION__);
		return false;
	}

	BYTE pBuffer[sizeof(NDISUIO_SET_OID) + sizeof(NDIS_802_11_SSID)];
	PNDISUIO_SET_OID pNDISUIOSetOid = (PNDISUIO_SET_OID) pBuffer;
	PNDIS_802_11_SSID pSsid = (PNDIS_802_11_SSID) pNDISUIOSetOid->Data;

	pNDISUIOSetOid->ptcDeviceName = (PTCHAR) pAdapter;
	pNDISUIOSetOid->Oid = OID_802_11_SSID;

	//ssid must be set as ANSI string
	pSsid->SsidLength = min(strlen(sAPName), sizeof(pSsid->Ssid));
	memset(pSsid->Ssid, 0, sizeof(pSsid->Ssid));
	memcpy(pSsid->Ssid, sAPName, pSsid->SsidLength);

	dwBytesReturned=0;

	LOCK;
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_SET_OID_VALUE, pBuffer, sizeof(pBuffer), 
		NULL, 0, &dwBytesReturned, NULL))
	{
		UNLOCK;
		logmsg("%s failed with error code %d", __FUNCTION__, GetLastError());
		return false;
	}
	UNLOCK;

	logmsg("%s succeeded.", __FUNCTION__);
	return true;	
}

//////////////////////////////////////////////////////////////////////////
bool CWifiPeek::ConnectToMACAddress(LPWSTR pAdapter, BYTE *pMac)
{
DWORD dwBytesReturned;

	logmsg("%s started...", __FUNCTION__);

	BYTE pBuffer[sizeof(NDISUIO_SET_OID) + sizeof(NDIS_802_11_MAC_ADDRESS)];
	PNDISUIO_SET_OID pNDISUIOSetOid = (PNDISUIO_SET_OID) pBuffer;

	pNDISUIOSetOid->ptcDeviceName = (PTCHAR) pAdapter;
	pNDISUIOSetOid->Oid = OID_802_11_BSSID;
	memcpy(pNDISUIOSetOid->Data, pMac, sizeof(NDIS_802_11_MAC_ADDRESS));

	dwBytesReturned=0;

	LOCK;	
	if(!DeviceIoControl(m_hNDUIO, IOCTL_NDISUIO_SET_OID_VALUE, 
		pBuffer, sizeof(pBuffer), NULL, 0, &dwBytesReturned, NULL))
	{
		UNLOCK;
		logmsg("%s failed with error code %d", __FUNCTION__, GetLastError());
		return false;
	}
	UNLOCK;

	logmsg("%s succeeded.", __FUNCTION__);
	return true;	
}

//////////////////////////////////////////////////////////////////////////
//Daniel Strigl's dhcp routines: renew and release
bool CWifiPeek::RenewIpAddress(LPWSTR pAdapter)
{
	PIP_INTERFACE_INFO pInfo = NULL;
	ULONG ulOutBufLen = 0;

	logmsg("%s started...", __FUNCTION__);
	LOCK;

	DWORD dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);

	if (dwRetVal == ERROR_INSUFFICIENT_BUFFER)
	{
		pInfo = (PIP_INTERFACE_INFO) malloc(ulOutBufLen);
		dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);
	}

	if (dwRetVal != NO_ERROR)
	{
		if (pInfo != NULL) 
		{
			free(pInfo);
		}

		logmsg("%s: GetInterfaceInfo failed with %d", __FUNCTION__, dwRetVal);
		UNLOCK;	
		return false;
	}

	LONG idx = 0;

	for (; idx < pInfo->NumAdapters; ++idx)
	{
		if(wcscmp(pInfo->Adapter[idx].Name, pAdapter) == 0)
			break;
	}

	//beyond the last item?
	if (idx == pInfo->NumAdapters)
	{
		free(pInfo);

		logmsg("%s: adapter %S not found.", __FUNCTION__, pAdapter);
		UNLOCK;
		return false;
	}

	dwRetVal = IpRenewAddress(&(pInfo->Adapter[idx]));

	if(dwRetVal != NO_ERROR)
	{
		free(pInfo);
		logmsg("%s: IpRenewAddress failed with %d", __FUNCTION__, dwRetVal);
		UNLOCK;
		return false;
	}
	UNLOCK;

	free(pInfo);
	logmsg("%s succeeded.", __FUNCTION__);
	return true;
}

//////////////////////////////////////////////////////////////////////////
bool CWifiPeek::ReleaseIpAddress(LPWSTR pAdapter)
{
	PIP_INTERFACE_INFO pInfo = NULL;
	ULONG ulOutBufLen = 0;

	logmsg("%s started...", __FUNCTION__);
	LOCK;

	DWORD dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);

	if (dwRetVal == ERROR_INSUFFICIENT_BUFFER)
	{
		pInfo = (PIP_INTERFACE_INFO) malloc(ulOutBufLen);
		dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);
	}

	if (dwRetVal != NO_ERROR)
	{
		if (pInfo != NULL) 
		{
			free(pInfo);
		}

		logmsg("%s: GetInterfaceInfo failed with %d", __FUNCTION__, dwRetVal);
		UNLOCK;	
		return false;
	}

	LONG idx = 0;

	for (; idx < pInfo->NumAdapters; ++idx)
	{
		if(wcscmp(pInfo->Adapter[idx].Name, pAdapter) == 0)
			break;
	}

	//beyond the last item?
	if (idx == pInfo->NumAdapters)
	{
		free(pInfo);

		logmsg("%s: adapter %S not found.", __FUNCTION__, pAdapter);
		UNLOCK;
		return false;
	}

	dwRetVal = IpReleaseAddress(&(pInfo->Adapter[idx]));

	if(dwRetVal != NO_ERROR)
	{
		free(pInfo);
		logmsg("%s: IpReleaseAddress failed with %d", __FUNCTION__, dwRetVal);
		UNLOCK;
		return false;
	}
	UNLOCK;

	free(pInfo);
	logmsg("%s succeeded.", __FUNCTION__);
	return true;
}

//////////////////////////////////////////////////////////////////////////
//WPA, WPA2 detection routine from Pier Paolo Neri
//returns:	-1 on error,
//Ndis802_11AuthModeWPA_XP or Ndis802_11AuthModeWPA2_XP on success
int CWifiPeek::GetAuthModeFromIEs(BYTE *pIE, size_t ie_len)
{
BYTE *pPos, *pEnd;
int proto;
	
	pPos = pIE;
	pEnd = pIE + ie_len;
	proto = 0;

	//something's wrong, there must be at least 3 fixed info elements, a struct _NDIS_802_11_FIXED_IEs
	if(ie_len < sizeof(NDIS_802_11_FIXED_IEs))
	{
		return -1;
	}

	//skip fixed IEs
	pPos += sizeof(NDIS_802_11_FIXED_IEs);

	//look for WPA or RSN IE
	while(pPos + 1 < pEnd && pPos + 2 + pPos[1] <= pEnd) 
	{
		BYTE ielen = 2 + pPos[1];

		if(ielen < 3)
		{
			logmsg("%s: bogus ielen: %d, exiting loop", __FUNCTION__, ielen);
			return -1;			
		}

		logmsg("%s: looping. Pos: %08x, ielen: %08x, End: %08x", __FUNCTION__, pPos, ielen, pEnd);

		if(ielen > SSID_MAX_WPA_IE_LEN)
		{
			//not what we're looking for, skip
			pPos += ielen;
			continue;
		}
		//WPA detected by GENERIC_INFO_ELEM and 4 bytes of fixed data
		if(pPos[0] == GENERIC_INFO_ELEM && pPos[1] >= 4 && memcmp(pPos + 2, WPA_OUI_TYPE, 4) == 0)
		{
			proto = Ndis802_11AuthModeWPA_XP;
		}
		//if it is a RSI_INFO_ELEM, must be WPA2
		else if(pPos[0] == RSN_INFO_ELEM)
		{
			proto = Ndis802_11AuthModeWPA2_XP;
		}
		pPos += ielen;
	}
	return proto;
}